<?php

declare (strict_types = 1);

namespace app\common\service\permission;

use app\common\exception\AdminException;
use app\common\repository\permission\MenuRepository;
use app\common\repository\permission\RoleRepository;
use app\common\service\BaseService;
use app\common\repository\permission\AdminRepository;
use app\common\service\system\AdminLoginLogService;
use app\common\util\JwtUtil;

class AdminService extends BaseService
{
    public function __construct(AdminRepository $repository)
    {
        $this->repository = $repository;
    }

    /**
     * 获取管理员分页列表
     *
     * @param array $params
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     */
    public function getList(array $params = []): array
    {
        [$page, $pageSize] = $this->getPaginationParams();
        $where = [];
        if(!empty($params['username'])){
            $where[] = ['username', 'like', '%'.$params['username'].'%'];
        }
        if(!empty($params['nickname'])){
            $where[] = ['nickname', 'like', '%'.$params['nickname'].'%'];
        }
        return $this->repository->paginate($where, ['id' => 'desc'], $page, $pageSize);
    }

    /**
     * 获取管理员详情信息
     *
     * @param $id
     * @return \app\common\model\BaseModel|array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getInfo($id): \app\common\model\BaseModel|array
    {
        $res = $this->repository->getOne($id)->toArray();
        $res['role_id'] = explode(',', $res['role_id']);
        return $res;
    }

    /**
     * 创建管理员信息
     *
     * @param array $data
     * @return \app\common\model\BaseModel|array|\think\Collection
     * @throws \Exception
     */
    public function create(array $data): \think\Collection|\app\common\model\BaseModel|array
    {
        $data['role_id'] = implode(',', $data['role_id']);
        $data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);
        return $this->repository->save($data);
    }

    /**
     * 更新管理员信息
     *
     * @param array $data
     * @param $id
     * @return \app\common\model\BaseModel|bool|int
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function update(array $data, $id): \app\common\model\BaseModel|bool|int
    {
        if(empty($id)) {
            throw new AdminException('ID 不能为空');
        }
        $data = [
            'username' => $data['username'],
            'nickname' => $data['nickname'],
            'password' => $data['password'],
            'avatar' => $data['avatar'],
            'phone' => $data['phone'],
            'email' => $data['email'],
            'status' => $data['status'],
            'role_id' => implode(',', $data['role_id']),
            'desc' => $data['desc'],
        ];
        if(!empty($data['password'])) {
            $data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);
        } else {
            unset($data['password']);
        }
        return $this->repository->update($data, $id);
    }

    /**
     * 删除管理员信息
     *
     * @param $id
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function delete($id): bool
    {
        return $this->repository->delete($id);
    }

    /**
     * 管理员登录
     *
     * @param $params
     * @return string
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function login($params): string
    {
        $res = $this->repository->getOne(['username' => $params['username']]);
        if(empty($res)) {
            $this->recordLoginLog(null, false, $params['username']);
            throw new AdminException('账号或密码不正确'); // 账号不存在
        }
        if (!password_verify($params['password'], $res->password)) {
            // 失败登录日志
            $this->recordLoginLog(null, false, $params['username']);
            throw new AdminException('账号或密码不正确');
        }
        // 成功登录日志
        $this->recordLoginLog($res, true);
        return JwtUtil::generateToken($res->id, 'admin');
    }

    /**
     * 记录登录日志
     *
     * @param object|null $admin
     * @param bool $status
     * @param string|null $username
     * @return void
     * @throws \Exception
     */
    private function recordLoginLog(?object $admin, bool $status, string $username = null): void
    {
        $data = [
            'admin_id'   => $admin ? $admin->id : 0,
            'username'   => $admin ? $admin->username : $username,
            'login_time' => date('Y-m-d H:i:s'),
            'login_ip'   => request()->ip(),
            'user_agent' => request()->header('User-Agent'),
            'status'     => $status ? 1 : 0,
        ];
        $adminLoginService = app()->make(AdminLoginLogService::class);
        $adminLoginService->create($data);
    }

    /**
     * 获取管理员登录信息
     *
     * @param $id
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getAdminInfo($id): array
    {
        if(empty($id)) {
            throw new AdminException('ID 不能为空');
        }
        $userInfo = $this->repository->getOne($id)->toArray();
        if($userInfo['role_id']) {
            $role_id = explode(',', $userInfo['role_id']);
            $roleService = app()->make(RoleService::class);
            $userInfo['role'] = $roleService->getByWhere([['id', 'in', $role_id]]);
        }
        return $userInfo;
    }

    /**
     * 获取管理员菜单路由
     *
     * @param $id
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getMenuRoutes($id): array
    {
        if (empty($id)) {
            throw new AdminException('ID 不能为空');
        }

        // 如果是超级管理员（id == 1）||超级管理角色，直接获取所有启用的菜单
        if ($id == 1) {
            $menuService = app()->make(MenuService::class);
            $menuList = $menuService->getByWhere([
                ['status', '=', 1],
                ['is_show', '=', 1],
                ['type', '=', 0]
            ], ['order' => 'desc'])->toArray();

            // 菜单列表转为树形结构
            $menuTree = build_tree($menuList);

            // 将菜单转为 Vue Router 格式
            return $this->convertMenuTreeToRoutes($menuTree);
        }

        // 获取用户信息
        $userInfo = $this->repository->getOne($id)->toArray();
        if (empty($userInfo['role_id'])) {
            return [];
        }

        // 获取角色 ID 列表
        $roleIds = explode(',', $userInfo['role_id']);

        // 获取角色对应的菜单 ID 列表
        $roleService = app()->make(RoleService::class);
        $menuIds = $roleService->getColumn('menu_ids', [['id', 'in', $roleIds]]);

        // 合并并去重菜单 ID
        $mergedMenuIds = [];
        foreach ($menuIds as $menuId) {
            $ids = array_map('intval', explode(',', $menuId));
            $mergedMenuIds = array_merge($mergedMenuIds, $ids);
        }
        $mergedMenuIds = array_values(array_unique($mergedMenuIds));

        // 获取有效的菜单列表
        $menuService = app()->make(MenuService::class);
        $menuList = $menuService->getByWhere([
            ['id', 'in', $mergedMenuIds],
            ['status', '=', 1],
            ['type', '=', 0]
        ], ['order' => 'desc'])->toArray();

        // 菜单列表转为树形列表
        $menuTree = build_tree($menuList);
        // 将菜单转为Vue Router格式
        $routes = $this->convertMenuTreeToRoutes($menuTree);
        return $routes;
    }

    /**
     * 将菜单树转换为 Vue Router 格式
     *
     * @param array $menuTree
     * @return array
     */
    protected function convertMenuTreeToRoutes(array $menuTree): array
    {
        $routes = [];
        foreach ($menuTree as $menu) {
            // 构造路由对象
            $route = [
                'id' => $menu['id'],
                'path' => $menu['route'],
                'name' => $menu['name'],
                'component' => $menu['component'],
                'meta' => [
                    'title' => $menu['title'],
                    'icon' => $menu['icon'],
                    'cache' => (bool)$menu['is_cache'],
                    'show' => (bool)$menu['is_show'],
                    'permission' => $menu['permission'],
                    'order' => $menu['order'],
                ]
            ];

            // 如果有子菜单，递归处理
            if (!empty($menu['children'])) {
                $route['children'] = $this->convertMenuTreeToRoutes($menu['children']);
            }

            $routes[] = $route;
        }

        return $routes;
    }

    /**
     * 获取权限标识列表
     *
     * @param $id
     * @return mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getPermissions($id): mixed
    {
        if (empty($id)) {
            throw new AdminException('ID 不能为空');
        }

        // 缓存键
        $cacheKey = 'permissions_' . $id;

        // 尝试从缓存中获取数据
        $permissionList = cache($cacheKey);
        if (!empty($permissionList)) {
            return $permissionList;
        }

        // 获取用户信息
        $userInfo = $this->repository->getOne($id)->toArray();
        if (empty($userInfo['role_id'])) {
            return [];
        }

        $menuService = app()->make(MenuRepository::class);

        // 超级管理员
        if($userInfo['id'] === 1) {
            return $menuService->getColumn('permission');
        }

        // 获取角色 ID 列表
        $roleIds = explode(',', $userInfo['role_id']);

        // 获取角色对应的菜单 ID 列表
        $roleService = app()->make(RoleRepository::class);
        $menuIds = $roleService->getColumn('menu_ids', [['id', 'in', $roleIds]]);

        $menuIds = explode(',', $menuIds[0]);

        $permissionList = $menuService->getColumn('permission', [['id', 'in', $menuIds]]);

        // 将结果存入缓存，缓存时间为 1 小时
        cache($cacheKey, $permissionList, 3600);

        return $permissionList;
    }

    /**
     * 修改管理员密码
     *
     * @param $data
     * @param $user_id
     * @return \app\common\model\BaseModel|bool|int
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function changePassword($data, $user_id): \app\common\model\BaseModel|bool|int
    {
        $user = $this->repository->getOne($user_id);
        // 验证旧密码是否正确
        if (!password_verify($data['old_password'], $user->password)) {
            throw new AdminException('原密码错误');
        }
        $password = password_hash($data['password'], PASSWORD_DEFAULT);
        return $this->repository->update([
            'password' => $password
        ], ['id' => $user_id]);
    }
}